package com.yeskery.nut.extend.memory;

import com.yeskery.nut.application.ServerEventContext;
import com.yeskery.nut.core.NutException;
import com.yeskery.nut.plugin.ApplicationContextSupportBasePlugin;
import com.yeskery.nut.plugin.PluginBeanMetadata;
import com.yeskery.nut.plugin.ServerEventPlugin;
import com.yeskery.nut.util.StringUtils;

import java.io.*;
import java.util.Collection;
import java.util.Collections;
import java.util.logging.Logger;

/**
 * 基于内存存储的插件
 * @author sprout
 * @version 1.0
 * 2022-06-03 11:49
 */
public class MemoryPlugin extends ApplicationContextSupportBasePlugin implements ServerEventPlugin {

    /** 日志对象 */
    private static final Logger logger = Logger.getLogger(MemoryPlugin.class.getName());

    /** Storage文件的名称 */
    private static final String STORAGE_FILE_NAME = "storage_memory_file.bin";

    /** 路径分隔符 */
    private static final String PATH_SEPARATOR = "/";

    /** Storage文件的存储路径 */
    private String path;

    /** 存储接口 */
    private Storage storage;

    /**
     * 构建一个基于内存存储的插件
     * @param path Storage文件的存储路径
     */
    public MemoryPlugin(String path) {
        if (StringUtils.isEmpty(path)) {
            throw new NutException("Path Must Not Be Empty.");
        }
        if (!path.endsWith(PATH_SEPARATOR) && !path.endsWith(File.separator)) {
            path += PATH_SEPARATOR;
        }
        this.path = path;
    }

    /**
     * 构建一个基于内存存储的插件
     */
    public MemoryPlugin() {
    }

    @Override
    protected Collection<PluginBeanMetadata> getRegisterPluginBeanMetadata() {
        if (!StringUtils.isEmpty(path)) {
            File storageFile = new File(path + STORAGE_FILE_NAME);
            if (!storageFile.exists()) {
                logger.info("Storage File Not Found.");
                return Collections.singletonList(new PluginBeanMetadata("storage", new DefaultStorage(),
                        Storage.class, DefaultStorage.class));
            }
            if (!storageFile.canRead()) {
                throw new NutException("Storage Path Can Not Read.");
            }
            try (FileInputStream fis = new FileInputStream(storageFile);
                 ObjectInputStream ois = new ObjectInputStream(fis)) {
                Object object = ois.readObject();
                if (!(object instanceof Storage)) {
                    throw new NutException("Unknown Storage Class.");
                }
                storage = (Storage) object;
            } catch (IOException e) {
                throw new NutException("Storage File Load Fail.", e);
            } catch (ClassNotFoundException e) {
                throw new NutException("Unknown Storage File Format.", e);
            }
        }

        if (storage == null) {
            storage = new DefaultStorage();
        }
        return Collections.singletonList(new PluginBeanMetadata("storage", storage,
                Storage.class, DefaultStorage.class));
    }

    @Override
    public void beforeClose(ServerEventContext serverEventContext) {
        if (storage != null && !storage.isEmpty() && !StringUtils.isEmpty(path)) {
            File storageFile = new File(path + STORAGE_FILE_NAME);
            if (storageFile.exists() && !storageFile.canWrite()) {
                throw new NutException("Storage Path Can Not Write.");
            }
            try (FileOutputStream fos = new FileOutputStream(storageFile);
                 ObjectOutputStream oos = new ObjectOutputStream(fos)) {
                oos.writeObject(storage);
                oos.flush();
            } catch (IOException e) {
                throw new NutException("Storage File Store Fail.", e);
            }
        }
    }
}
